﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc;
using Autofac;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using yiCommerce.Core;
using yiCommerce.Core.Domain.Statuses;
using yiCommerce.Models.Statuses;
using yiCommerce.Service.Customers;
using yiCommerce.Service.FriendShips;
using yiCommerce.Service.Products;
using yiCommerce.Service.Statuses;

namespace yiCommerce.Hubs
{
    [HubName("statuses")]
    public class StatusesHub:Hub
    {

        private IStatusService _statusService;
        private IWorkContext _workContext;

       readonly ILifetimeScope _hubLifetimeScope;
        private IFriendShipService _friendShipService;
        private ICustomerService _customerService;
        private IProductService _productService;

        public StatusesHub(ILifetimeScope lifetimeScope)
        {
            // Create a lifetime scope for the hub.
            //_hubLifetimeScope = lifetimeScope.BeginLifetimeScope();

            //// Resolve dependencies from the hub lifetime scope.
            ////_workContext = _hubLifetimeScope.Resolve<IWorkContext>();
            //_statusService = _hubLifetimeScope.Resolve<IStatusService>();

            _workContext = DependencyResolver.Current.GetService<IWorkContext>();
            _statusService = DependencyResolver.Current.GetService<IStatusService>();
            _friendShipService = DependencyResolver.Current.GetService<IFriendShipService>();
            _customerService= DependencyResolver.Current.GetService<ICustomerService>();
            _productService = DependencyResolver.Current.GetService<IProductService>();
        }

        protected override void Dispose(bool disposing)
        {
            // Dipose the hub lifetime scope when the hub is disposed.
            if (disposing && _hubLifetimeScope != null)
                _hubLifetimeScope.Dispose();

            base.Dispose(disposing);
        }

        private static readonly ConcurrentDictionary<string, CustomerConnection> customerConnections = new ConcurrentDictionary<string, CustomerConnection>(StringComparer.InvariantCultureIgnoreCase);

        //private   Dictionary<string, Receiver> receivers = new Dictionary<string, Receiver>()
        //    {
        //        {"dd@dd.com", new Receiver(){Name = "dd@dd.com", Receivers = new List<string>(){"dd@dd.com","cc@cc.com"}}}
        //    };

     
        public override Task OnConnected()
        {
            string userName = Context.User.Identity.Name;
            string connectionId = Context.ConnectionId;

            var newConnection = customerConnections.GetOrAdd(userName, _ => new CustomerConnection()
                {
                    Name = userName,
                    ConnectionIds = new List<string>()
                });

            newConnection.ConnectionIds.Add(connectionId);

            return base.OnConnected();
        }


        private CustomerConnection GetConnection(string username)
        {

            CustomerConnection connection;
            customerConnections.TryGetValue(username, out connection);

            return connection;
        }

        public void SendProductStatus(ProductStatusMessage message)
        {
            var request = new ProductInfoInsertRequest()
                {
                    ProductName = string.Empty,
                    FullDescription = message.Text,
                    StockQuantity = message.ProductStock,
                    Price = message.ProductPrice,
                    PictureIds = message.Pics.Select(c => c.PicId).ToList(),
                    IsPublished = true
                };

            request.ShopId =_workContext.CurrentCustomer.Shop.Id;

            var result = _productService.InsertProductInfo(request);

            if (result.Success)
            {
                
                var status = _statusService.Update(message.Text, _workContext.CurrentCustomer.Id, message.Pics.Select(c => c.PicId).ToList(), true, result.Id,null);
                this.ClientReceive(status,true);
            }

        }

        public void Send(StatusModel message)
        {
            //CustomerConnection sender = GetConnection(Context.User.Identity.Name);
            
            var status = _statusService.Update(message.Text, _workContext.CurrentCustomer.Id, message.Pics.Select(c=>c.PicId).ToList(), false, null,message.Tags);


            ClientReceive(status, false);
        }

        private void ClientReceive(Status status, bool isProductStatus)
        {
            Receiver receiver = GetReceivers(Context.User.Identity.Name);
            var receivres = receiver.Receivers;

            foreach (var receivreName in receivres)
            {
                CustomerConnection receiverConnections = GetConnection(receivreName);
                if (receiverConnections != null)
                {
                    var connIds = receiverConnections.ConnectionIds;
                    foreach (var connId in connIds)
                    {
                        var statusModel = yiCommerce.Mapper.StatusMapper.ToStatusListItemModel(status);
                        Clients.Client(connId).messageReceived(statusModel);
                        var receiverStatus = new ReceiverStatus()
                            {
                                IsProductStatus = isProductStatus,
                                Status = "success"
                            };
                        Clients.Caller.success(receiverStatus);
                    }
                }
            }
        }

        private Receiver GetReceivers(string email)
        {

            var customer = _customerService.GetCustomerByEmail(email);
            var friends = _friendShipService.Fans(customer.Id);
            var receiver = new Receiver()
                {
                    Name = email,
                    Receivers = friends.Select(c => c.Email).ToList()
                };

            //add me
            receiver.Receivers.Add(email);
            return receiver;
        }

        public override Task OnDisconnected()
        {

            string userName = Context.User.Identity.Name;
            string connectionId = Context.ConnectionId;

            CustomerConnection connection;
            customerConnections.TryGetValue(userName, out connection);

            connection.ConnectionIds.Remove(connectionId);

            return base.OnDisconnected();
        }
         
    }

    public class ProductStatusMessage
    {
        public string Text { get; set; }
        public IList<StatusPictureModel> Pics { get; set; }
        public bool IsProduct { get; set; }
        public int ProductStock { get; set; }
        public decimal ProductPrice { get; set; }
    }

    public class ReceiverStatus
    {
        public string Status { get; set; }
        public bool IsProductStatus { get; set; }
    }
}